package com.woniu.project.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniu.project.core.domain.*;
import com.woniu.project.core.exception.ProjectAuthenException;
import com.woniu.project.core.exception.ProjectExceptionCode;
import com.woniu.project.core.utils.JwtUtil;
import com.woniu.project.dao.*;
import com.woniu.project.dto.*;
import com.woniu.project.params.*;
import com.woniu.project.service.ManagementService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.project.service.PermissionService;
import com.woniu.project.service.RoleService;
import com.woniu.project.web.common.DateCommon;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Klaus
 * @since 2020-10-13
 */
@Service
public class ManagementServiceImpl extends ServiceImpl<ManagementMapper, Management> implements ManagementService {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private ManagementMapper managementMapper;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private ManagementRoleMapper managementRoleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private PermissionTypeMapper permissionTypeMapper;

    @Autowired
    private RolePermissionMapper rolePermissionMapper;


    /**
     * 发送短信的服务
     * 发送异步消息
     * @param ManagementPhone 手机号码
     */
    @Override
    public void sendMsg(String ManagementPhone) {
        SendResult sendResult = rocketMQTemplate.syncSend("message:"+ManagementPhone, ManagementPhone);
        rocketMQTemplate.asyncSend("message:" + ManagementPhone,ManagementPhone, new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println("这个是消息队列发送成功的返回："+sendResult);
            }

            @Override
            public void onException(Throwable throwable) {
                System.out.println("这个是消息队列发送失败的返回：");
            }
        });
    }


    /**
     * 管理员登录 判断账号密码是否正确 短信验证码是否正确
     * 如果均正确，则将赋予对应的token
     * @return
     */
    @Override
    public String login(ManagementParams managementParams) {
        System.out.println("进入~~~~~~~~~~~~~~~~~~");
        //判断验证码是否正确
        String managementPhone = managementParams.getManagementPhone();
        String messageCode = managementParams.getMessageCode();
        String managementPassword = managementParams.getManagementPassword();

        //从redis中取出的短信验证码
        String code = redisTemplate.opsForValue().get("messageCode:" + managementPhone + ":");
        System.out.println(code +"-------------");
        if (!(messageCode!=null && messageCode.equals(code)))
            //如果填入的验证码为空或者验证码错误、过期
            throw new ProjectAuthenException(ProjectExceptionCode.USER_AUTHE_MESSAGECODE_ERROR);

        //如果验证码正确，判断账号密码是否匹配
        Management management = managementMapper.selectManagementByPhoneAndPassword(managementPhone, managementPassword);
        if (management==null)
            //如果查询出的结果为空 则代表错误的账号密码
            throw new ProjectAuthenException(ProjectExceptionCode.USER_AUTHE_ERROR);
        if(management.getManagementStatus().equals("禁用"))
            //如果该账号状态为禁用，则返回提示
            throw new ProjectAuthenException(ProjectExceptionCode.USER_AUTHE_DISABLED);

        //如果账号密码匹配，则将该用户的所有权限放入到TOKEN
        //① 查询出该用户的所有角色
        List<RoleDto> roleDtos = roleService.selectRoleByManagementId(management.getManagementId());
        //如果没有查询出任何角色，代表该账号没有进行过任何授权
        if (roleDtos == null)
            throw new ProjectAuthenException(ProjectExceptionCode.USER_UNAUTHORIZED);
        /*
            创建一个hash，用于储存查询出来的这个管理员对应的权限
            key:PermissionTypeDto --->权限对应的权限类别
            value:PermissionDto   --->权限
         */
        Map<String,Object> permissions = new HashMap<>();
        //将管理员的信息存入到这个hash中
        permissions.put("managementId",management.getManagementId());
        permissions.put("managementName",management.getManagementName());
        permissions.put("managementPhone",management.getManagementPhone());
        permissions.put("managementStatus",management.getManagementStatus());

        //② 循环遍历，根据角色ID查询出角色对应的所有权限，并将其插入permissions中
        List<PermissionDto> permissionDtos = new ArrayList<>();
        for (RoleDto roleDto : roleDtos) {
            permissionDtos = permissionService.selectRoleByRoleId(roleDto.getRoleId());
        }
        System.out.println("permissionDtos=================" + permissionDtos);
        //遍历权限集合，将路径插入permissions中
        List<String> permissionAddrs = new ArrayList<>();
        int cont = 0;
        for (PermissionDto permissionDto : permissionDtos) {
            System.out.println("cont========="+cont++);
            String permissionAddr = permissionDto.getPermissionAddr();
            permissionAddrs.add(permissionAddr);
        }
        permissions.put("permissionAddrs",permissionAddrs);


//        for (PermissionDto permissionDto : permissionDtos) {
//            String permissionAddr = permissionDto.getPermissionAddr();
//            Integer permissionId = permissionDto.getPermissionId();
//            String permissionName = permissionDto.getPermissionName();
//            //创建一个hashmap用于储存权限信息
//            HashMap<String, String> pp = new HashMap<String, String>();
//            pp.put("permissionAddr",permissionAddr);
//            pp.put("permissionName",permissionName);
//
//
//            Integer permissionTypeId = permissionDto.getPermissionTypeId();
//
//            //创建一个hashmap 用于储存权限的相关信息
//            HashMap<String, String> permission = new HashMap<>();
//
//            //遍历 permissions 判断中是否已经包含了这个类型
//            boolean flag = false;
//            for (Map.Entry<String, Object> p : permissions.entrySet()) {
//                String key = p.getKey();
//                //如果permissions中已经包含了这个权限类别，则直接新增即可
//                if (key.equals("permissionTypeId:"+permissionTypeId)){
//                    //获取 permissions 这层中的value
//                    //对应的关系为 permissionTypeId: HashMap<String, Object>
//                    //其中的String 为对应的权限ID
//                    //Object 为HashMap<String, String> 用于储存pp 中的内容 也就是地址和名字
//                    HashMap<String, Object> value =(HashMap<String, Object>) p.getValue();
//                    value.put("permissionId:"+permissionId,pp);
//                    p.setValue(value);
//                    flag = true;
//                    break;
//                }
//            }
//            //如果为false  代表之前没有存过这个权限类型 新增即可
//            if (flag == false){
//                HashMap<String, Object> value = new HashMap<>();
//                value.put("permissionId:"+permissionId,pp);
//                permissions.put("permissionTypeId:"+permissionTypeId,value);
//            }
//            flag =false;
//        }
        System.out.println("permissions>>>>>>>>>>"+permissions);

        //③ 将 permissions 的数据存入到token
        String token = JwtUtil.creatToken(permissions, 2 * 60 * 60);
        return token;

    }


    /**
     * 新增管理员
     *
     * @param managementParams managementParams必须传入三个参数
     *                         managementName 用户名
     *                         managementPassword 密码
     *                         managementPhone 手机号
     * @return
     */
    @Override
    public void addManagement(ManagementParams managementParams) {
        //根据手机号和用户名查询是否已经注册过账号
        Management oldManagement = managementMapper.SelectManageMentByPhoneOrName(managementParams.getManagementPhone(), managementParams.getManagementName());
        if (oldManagement != null)
           throw new ProjectAuthenException(ProjectExceptionCode.USER_REGISTERED);
        Management management = new Management();
        BeanUtils.copyProperties(managementParams,management);

        //获取当前时间
        LocalDateTime creatDate = DateCommon.getLocalDate(new Date());
        management.setManagementAddTime(creatDate);

        management.setManagementAddTime(creatDate);
        management.setManagementStatus("正常");

        //新增管理员
        managementMapper.insert(management);
    }

    /**
     * 分页查询所有的管理员
     * @param selectParam
     * @return
     */
    @Override
    public IPage<ManagementDto> selectAllManagement(SelectParam selectParam) {
        Page<Management> page = new Page<>(selectParam.getPage(), selectParam.getSize());

        //条件构造器
        QueryWrapper<Management> wrapper = new QueryWrapper<Management>();
        IPage ipage = page(page, wrapper);

        //将Management转为ManagementDto
        List<Management> records = ipage.getRecords();
        List<ManagementDto> managementDtos = new ArrayList<>();
        for (Management record : records) {
            ManagementDto managementDto = new ManagementDto();
            BeanUtils.copyProperties(record,managementDto);
            managementDtos.add(managementDto);
        }
        ipage.setRecords(managementDtos);
        return ipage;
    }

    /**
     * 修改管理员状态
     *
     * @param managementParams managementId 管理员ID
     *                         managementStatus 修改后的管理员的状态
     * @return
     */
    @Override
    public void changeManagementStatus(ManagementParams managementParams) {
        Integer managementId = managementParams.getManagementId();
        String managementStatus = managementParams.getManagementStatus();
        //先根据ID查询对应管理员信息
        Management management = managementMapper.selectById(managementId);
        //如果管理员查询无果，返回错误信息
        if(management == null)
            throw new ProjectAuthenException(ProjectExceptionCode.USER_NOTFOUND);
        //判断管理员账号的状态是否与需要修改的状态一致，如果一致，则返回错误信息
        if(management.getManagementStatus().equals(managementStatus))
            throw new ProjectAuthenException(ProjectExceptionCode.USER_SAMESTATUS);

        //如果查询到对应的管理员账号，并且状态与本身状态不一致，则修改其状态
        management.setManagementStatus(managementStatus);
        managementMapper.updateById(management);
    }

    /**
     * 修改管理员的密码
     *
     * @param managementParams managementId 管理员ID
     *                         managementOldPassworld  管理员旧密码
     *                         managementNewPassworld  管理员新密码
     * @return
     */
    @Override
    public void changeManagementPassword(ManagementChangePasswordParams managementParams) {
        Integer managementId = managementParams.getManagementId();
        String managementNewPassword = managementParams.getManagementNewPassword();
        String managementOldPassword = managementParams.getManagementOldPassword();

        System.out.println("managementNewPassword---------"+managementNewPassword);
        System.out.println("managementOldPassword---------"+managementOldPassword);
        //判断新旧密码是否一致 如果一致则无需修改
        if(managementNewPassword.equals(managementOldPassword))
            throw new ProjectAuthenException(ProjectExceptionCode.USER_PASSWORD_SAME);

        //判断旧密码是否正确
        Management management = managementMapper.selectById(managementId);
        if (!management.getManagementPassword().equals(managementOldPassword))
            throw new ProjectAuthenException(ProjectExceptionCode.USER_PASSWORD_ERROR);

        //如果输入的密码正确，则修改密码
        management.setManagementPassword(managementNewPassword);
        managementMapper.updateById(management);
    }

    /**
     * 新增管理员的角色
     *
     * @param roleParams roleName 角色名
     *                   roleDescription 角色描述
     * @return
     */
    @Override
    public void addRole(RoleParams roleParams) {
        String roleName = roleParams.getRoleName();
        System.out.println();
        //判断角色名是否重复
        Role ro = roleMapper.selectRoleByName(roleName);
        if (ro != null)
            throw new ProjectAuthenException(ProjectExceptionCode.USER_ROLENAME_REGISTERED);

        //如果角色不重复，则新增角色
        Role role = new Role();
        BeanUtils.copyProperties(roleParams,role);
        roleMapper.insert(role);
    }

    /**
     * 给管理员分配角色
     *
     * @param roleManagementParams
     * @return roleManagementParams
     * managementId 管理员ID
     * roleIdList 角色ID的集合
     */
    @Override
    public void allocationRole(RoleManagementParams roleManagementParams) {
        Integer managementId = roleManagementParams.getManagementId();
        //需要更新给管理员的角色ID
        List<Integer> roleIdList = roleManagementParams.getRoleIdList();
        //管理员现在的所有角色
        List<ManagementRole> managementRoles = managementRoleMapper.selectRoleByManagementId(managementId);

        //先进行新增
        //遍历角色ID集合，再遍历所有角色集合，找出没有的角色并新增
        boolean flag = false;
        for (Integer roleId : roleIdList) {
            for (ManagementRole managementRole : managementRoles) {
                Integer roleId1 = managementRole.getRoleId();
                if (roleId == roleId1){
                    flag = true;
                    break;
                }
            }
            //如果遍历完当前所有的角色ID，都没有，则进行新增
            if (flag == false){
                ManagementRole managementRole = new ManagementRole();
                managementRole.setManagementId(managementId);
                managementRole.setRoleId(roleId);
                managementRoleMapper.insert(managementRole);
            }
            flag = false;
        }
        flag = false;
        //再进行删除
        //遍历所有角色集合，再遍历所有角色ID集合，找出没有的角色并删除
        for (ManagementRole managementRole : managementRoles) {
            Integer roleId = managementRole.getRoleId();
            for (Integer roleid1 : roleIdList) {
                if (roleId == roleid1){
                    flag = true;
                    break;
                }
            }
            //如果遍历完所有的角色集合，都没有，则进行删除
            if (flag == false){
                managementRoleMapper.deleteManagementRoleByManagementIdAndRoleId(managementId,roleId);
            }
            flag = false;
        }
    }

    /**
     * 查询所有管理员所有角色
     * @return
     */
    @Override
    public List<ManagementRoleDto> selectAllManagementRole() {
        //查询管理员和角色的中间表的所有数据
        List<ManagementRole> managementRoles = managementRoleMapper.selectAllList();

        //新建一个集合变量 用于储存最后的查询结果
        List<ManagementRoleDto> managementRoleDtos = new ArrayList<>();

        //遍历管理员角色中间表，将信息依次录入 managementRoleDtos
        for (ManagementRole managementRole : managementRoles) {
            Integer managementId = managementRole.getManagementId();
            Integer roleId = managementRole.getRoleId();
            //根据管理员ID查询管理员的信息
            Management management = managementMapper.selectById(managementId);
            //为了安全把管理员的密码信息设置为空
            management.setManagementPassword("");
            //根据角色ID查询角色的信息
            Role role = roleMapper.selectById(roleId);
            System.out.println("role-------"+role);
            //定义一个变量用于判断储存结果中是否包含对应的管理员
            boolean flag = false;

            //遍历 managementRoleDtos ，判断是否已经包含这个管理员
                if (managementRoleDtos != null){
                    for (ManagementRoleDto managementRoleDto : managementRoleDtos) {
                        ManagementDto management1 = managementRoleDto.getManagement();
                        List<RoleDto> roleDtos = managementRoleDto.getRoleDtos();
                        //先判断是否有这个管理员
                        if(management.getManagementId() == management1.getManagementId()){
                            //如果有这个管理员 直接添加角色即可
                            RoleDto roleDto = new RoleDto();
                            BeanUtils.copyProperties(role,roleDto);
                            roleDtos.add(roleDto);
                            managementRoleDto.setRoleDtos(roleDtos);
                            flag = true;
                        }
                    }
                    //判断flag 的值 如果不包含这个管理员则进行新增
                    if (flag == false){
                        ManagementRoleDto managementRoleDto = new ManagementRoleDto();
                        ManagementDto managementDto = new ManagementDto();
                        BeanUtils.copyProperties(management,managementDto);
                        managementRoleDto.setManagement(managementDto);

                        RoleDto roleDto = new RoleDto();
                        BeanUtils.copyProperties(role,roleDto);
                        List<RoleDto> roleDtos = new ArrayList<>();
                        roleDtos.add(roleDto);
                        managementRoleDto.setRoleDtos(roleDtos);

                        managementRoleDtos.add(managementRoleDto);
                    }
                    //如果managementRoleDtos 为null 直接新增
                }else {
                    ManagementRoleDto managementRoleDto = new ManagementRoleDto();
                    ManagementDto managementDto = new ManagementDto();
                    BeanUtils.copyProperties(management,managementDto);
                    managementRoleDto.setManagement(managementDto);

                    RoleDto roleDto = new RoleDto();
                    BeanUtils.copyProperties(role,roleDto);
                    List<RoleDto> roleDtos = new ArrayList<>();
                    roleDtos.add(roleDto);
                    managementRoleDto.setRoleDtos(roleDtos);

                    managementRoleDtos.add(managementRoleDto);
                }
        }

        return managementRoleDtos;
    }

    /**
     * 查询指定管理员所有角色
     * @param managementId
     * @return
     */
    @Override
    public List<RoleDto> selectOneManagementRole(String managementId) {
        int id = Integer.parseInt(managementId);
        //查询出这个管理员所有的角色ID
        List<ManagementRole> managementRoles = managementRoleMapper.selectRoleByManagementId(id);
        List<RoleDto> roleDtos = new ArrayList<>();
        for (ManagementRole managementRole : managementRoles) {
            Role role = roleMapper.selectById(managementRole.getRoleId());
            RoleDto roleDto = new RoleDto();
            BeanUtils.copyProperties(role,roleDto);
            roleDtos.add(roleDto);
        }
        return roleDtos;
    }

    /**
     * 查询权限列表
     *
     * @return
     */
    @Override
    public List<PermissionTypeAndPermissionDto> selectAllPermission() {
        //先查询出所有的权限
        List<Permission> permissions = permissionMapper.selectList();

        //新增一个集合用于储存最后的查询结果
        List<PermissionTypeAndPermissionDto> permissionTypeAndPermissionDtos = new ArrayList<>();

        //遍历所有的权限，根据每个权限的权限类别ID查询对应的权限类别
        for (Permission permission : permissions) {
            Integer permissionTypeId = permission.getPermissionTypeId();
            //根据权限类别ID查询对应的权限
            PermissionType permissionType = permissionTypeMapper.selectById(permissionTypeId);

            //新建一个变量 用于判断permissionTypeAndPermissionDtos 中是否包含某个权限类别
            Boolean flag = false;

            //遍历 permissionDtos 看一下是否包含这个权限类别
            for (PermissionTypeAndPermissionDto permissionTypeAndPermissionDto : permissionTypeAndPermissionDtos) {
                PermissionTypeDto permissionTypeDto = permissionTypeAndPermissionDto.getPermissionTypeDto();
                //如果有这个权限类别 则直接添加权限
                if (permissionTypeDto.getPermissionTypeId() == permissionType.getPermissionTypeId()){
                    List<PermissionDto> permissionDtos = permissionTypeAndPermissionDto.getPermissionDtos();
                    PermissionDto permissionDto = new PermissionDto();
                    BeanUtils.copyProperties(permission,permissionDto);
                    permissionDtos.add(permissionDto);
                    permissionTypeAndPermissionDto.setPermissionDtos(permissionDtos);
                    flag = true;
                    break;
                }
            }
            //判断 flag 的值，若为false 则代表不包含这个权限类别，新增即可
            if (flag == false){
                PermissionTypeAndPermissionDto permissionTypeAndPermissionDto = new PermissionTypeAndPermissionDto();
                PermissionTypeDto permissionTypeDto = new PermissionTypeDto();
                BeanUtils.copyProperties(permissionType,permissionTypeDto);
                permissionTypeAndPermissionDto.setPermissionTypeDto(permissionTypeDto);

                List<PermissionDto> permissionDtos = new ArrayList<>();
                PermissionDto permissionDto = new PermissionDto();
                BeanUtils.copyProperties(permission,permissionDto);
                permissionDtos.add(permissionDto);
                permissionTypeAndPermissionDto.setPermissionDtos(permissionDtos);

                permissionTypeAndPermissionDtos.add(permissionTypeAndPermissionDto);
            }
        }
        return permissionTypeAndPermissionDtos;
    }

    /**
     * 根据角色ID修改角色的权限
     *
     * @param rolePermissionParams
     * @return
     */
    @Override
    public void changeRolePermission(RolePermissionParams rolePermissionParams) {
        Integer roleId = rolePermissionParams.getRoleId();
        List<Integer> permissionIdList = rolePermissionParams.getPermissionIdList();

        //根据角色ID查询出这个角色对应的所有权限
        List<RolePermission> rolePermissions = rolePermissionMapper.selectPermissionByRoleId(roleId);

        //先进行新增
        //遍历权限ID集合，再遍历所有权限集合，找出没有的权限并新增
        boolean flag = false;
        for (Integer permissionId : permissionIdList) {
            for (RolePermission rolePermission : rolePermissions) {
                Integer permissionId1 = rolePermission.getPermissionId();
                //如果权限ID相同了，代表已经有该权限，则不进行操作
                if (permissionId == permissionId1){
                    flag = true;
                    break;
                }
            }
            //如果遍历完了 flag==false 则代表现有权限中没有该权限，进行新增操作
            if (flag == false){
                RolePermission rolePermission = new RolePermission();
                rolePermission.setRoleId(roleId);
                rolePermission.setPermissionId(permissionId);
                rolePermissionMapper.insert(rolePermission);
            }
            flag = false;
        }
        flag = false;
        //再进行删除
        //遍历所有权限集合，再遍历所有权限ID集合，找出没有的权限并删除
        for (RolePermission rolePermission : rolePermissions) {
            Integer permissionId = rolePermission.getPermissionId();
            for (Integer permissionId1 : permissionIdList) {
                //如果权限ID相同了，代表已经有该权限，则不进行操作
                if (permissionId == permissionId1){
                    flag = true;
                    break;
                }
            }
            //如果遍历完了 flag==false 则代表现有权限中多余了该权限，进行删除操作。
            if (flag == false){
                rolePermissionMapper.deletePermissionByRoleIdAndPermissionId(roleId,permissionId);
            }
            flag = false;
        }


    }


}
